#ifndef OUTPUT_H
#define OUTPUT_H
/***************************************************************************
 *   Copyright (C) 2004 - 2008 by Moritz Vieth                             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifdef DEBUG
#error "You have defined a symbol named DEBUG. This class will not be able to function,\
since it uses a (real) constant by that name. Please use a different name for that symbol\
(like APP_DEBUG__, for instance; you should use prefixes anyway), or change the source code of this class."
#else


#include <string>
#include <vector>


/**
 * This class provides useful methods for managing textual output of your
 * application.<br />
 * <br />
 * Each call of the messaging (#message and #hexdump) and logging (#log)
 * methods will get you some nicely formatted output. For any of these calls,
 * a debug level has to be specified. If this level does not exceed a given
 * threshold (as set by #setOutputLevel and #setLogLevel), the message will
 * be discarded.<br />
 * All output is completely threadsafe (no more 'stdout salad' by multiple
 * threads. Yay!).<br />
 * <br />
 * Each message call will result in a log call as well.
 * Messages with levels IMPORTANT and CRITICAL will be written to error.log,
 * all other to debug.log<br />
 * <br />
 * There are several properties of the class that can be configured by
 * calling the appropriate methods:<br />
 * <pre>
 * 
 * setOutputLevel(int):  sets the threshold for the textual (i.e. terminal) output
 * 
 * setLogLevel(int):    sets the threshold for the logging output.
 * 
 * setQuiet():          surpress ALL output
 * 
 * setTag(std::string): sets the application tag to print at the beginning of
 *                      each line, e.g. setTag("myApp") will result in:
 *                      [myApp] [DEBUG] <some debug message>
 * 
 * setApplicationInfo(std::string): Info (like version, build date etc) to print at
 *                      the beginning of each logging session
 * 
 * setLogPath(std::string): sets the path where to store your log files.
 * 
 * showFunctionNames(bool): specifies wether to print the function name where
 *                      the message call oroginated from or not. E.g.:
 *                      [myApp] [DEBUG] MyClass::someFunction: some debug message 
 *                      This is nice when debugging, but rather annoying on "normal" runs.
 *                      For this to work, the program has to be compiled using the
 *                      -pg flag and linked using the -rdynamic flag 
 * 
 * showParams(bool):    set wether function parameters shall be printed (when
 *                      printing function names, otherwise ignored). E.g.:
 *                      [myApp] [DEBUG] MyClass::someFunction(int,string): some debug message
 * 
 * useColors(bool:		set wether IMPORTANT and CRITICAL messages should be printed in red.
 * 						Works only on ANSI terminals by now (version 1.7).
 * 
 * addFunctionFilterString(std::string): adds strings to filter when displaying
 *                      function names. This is useful for instance when using
 *                      Qt applications, which will surround you "original" program
 *                      with loads of wrappers. 
 *                      *** EXPERIMENTAL ***
 * </pre>
 * <br />
 * <em>All those setup methods should be called before any "real" program logic (especially before
 * producing any output). Wrapping this in a method like setupOutput() may be a good idea ;)</em><br />
 * <br />
 * <br />
 * USAGE:<br />
 * just #include <Output.h> and call the static functions, e.g.<br />
 * <pre>
 * Output::setTag("SomeApp");
 * Output::showFunctionNames(false);
 * Output::message("Postion: (%d,%d)", Output::TESTING, pos.x, pos.y);
 * </pre>
 * will result in<br />
 * <pre>
 * [SomeApp] [DEBUG] Position: (120,340)
 * (or whatever 'pos' is...)
 * 
 * 
 * </pre>
 * The output methods are:
 * <pre>
 * message(string[, int]):  prints message to stdout. Level does not need to be given,
 *                          default is DEBUG
 * message(char* , int, ...): prints message to stdout, the good old printf way! (Output
 *                          level has to be the first parameter after the format string)
 * 
 * log(string[, int]):      same as above for logging.
 * log(char*, int, ...):    same as above for logging.
 * 
 * separator(string[, int]):
 * separator([int]):        prints a seperating line to stdout (without tags etc.).
 *                          Useful when working with (infinite) loops.
 *                          A different seperator than the standard one can be specified.
 * 
 * printApplicationInfo(std::string):
 * 							prints an informative string (if set by the user) about the
 * 							current application. Does not make use of any tags.
 * 
 * hexdump(string, uchar*, int, int, int):
 *                          hexdumps a byte array (e.g. an IP packet). The string is a
 *                          description for the array, width specifies how many bytes
 *                          per line should be printed. Rest should be self-explanatory ;)
 * 
 * printBacktrace(int[, int]):
 * printBacktrace(string, int[, int]):
 *                          As the name suggests, this prints a backtrace to stdout (leaving out
 *                          the Methods of this class), along with on (optional) note.
 *                          Optionally, you can specify if and how many level of the backtrace should
 *                          be left out, for instance to exclude the calling method.
 * 
 * </pre>
 * NOTE:
 * printBacktrace can be used conveniently to automatically do a backtrace after recieving
 * a segmentation fault.
 * This can be done by adding the following to the file containing your main method
 * <pre>
 ** #include <signal.h>
 ** 
 ** void term_func(int signal){
 ** 	Output::printBacktrace("Recieved Segmentation fault!", Output::CRITICAL, 2);
 ** 	exit(1);
 ** }
 ** 
 ** int main(){
 ** ...
 ** signal(SIGSEGV, term_func);
 ** ...
 ** }
 * </pre>
 * The same can be done for any signal, of course. 
 * 
 * 						
 * 
 * @author Moritz Vieth
 * @version 1.7
 */
class Output
{
	
public: //constants
	
	/* The all-defining level constants */
	static const int DEBUG;
	static const int TESTING;
	static const int VERBOSE;
	static const int IMPORTANT;
	static const int CRITICAL;
	static const int QUIET;
	
public: //methods
	
	
	/******************** setup methods ********************/
	static void setOutputLevel(int level);
	static void setLogLevel(int level);
	static void setQuiet();
	  
	static void setTag(std::string tag);
	static void setApplicationInfo(std::string info);
	  
	static void setLogPath(std::string path);
	/*******************************************************/
	
	
	
	/*************** inline configuration switches ***************/
	/** add a function name filter.
	 * @see Output::functionNameFilter */
	static inline void addFunctionFilterString(std::string filter){
		Output::functionNameFilter->push_back(filter); //see Output.cpp
	}
	 
	/** Toggle whether fuction names are shown in textual output. */
	static inline void showFunctionNames(bool doIt){
		Output::doShowFunctionNames = doIt;
	}
	
	/** Toggle whether parameters are shown after function names in textual output. */
	static inline void showParams(bool doIt){
		Output::doShowParams = doIt;
	}
	  
	/** Toggle whether line numbers are shown in textual output. NOT IMPLEMENTED YET */
	static inline void showLineNumbers(bool doIt){
		Output::doShowLineNumbers = doIt; //TODO not implemented yet
	}
	 
	/** Toggle whether file names are shown in textual output. NOT IMPLEMENTED YET */
	static inline void showFileNames(bool doIt){
		Output::doShowFileNames = doIt; //TODO not implemented yet
	}
	
	/** Toggle logging. */
	static inline void logMessages(bool doIt){
		Output::doLog = doIt;
	}
	
	/** Toggle color usage */
	static inline void useColors(bool doIt){
		Output::doUseColors = doIt;
	}
	/*************************************************************/
	
	
	/******************** output methods ********************/
	static void message(std::string msg, int level = Output::DEBUG);
	static void message(const char* msg, int level, ...);
	
	static void log(std::string msg, int level = Output::DEBUG);
	static void log(const char* msg, int level, ...);
	
	static void hexdump(std::string type, unsigned char* data, int length, int width, int level);
	
	static void printBacktrace(int level = Output::DEBUG, int stripLevels = 0);
	static void printBacktrace(std::string note, int level = Output::DEBUG, int stripLevels = 0);
	
	static void printApplicationInfo();
	  
	static void separator(std::string sep, int level = Output::DEBUG);
	static void separator(int level = Output::DEBUG);
	/********************************************************/
	  
	  
	/* the lonely getter */  
	static int getLevel();
	
	
	
  

private: //methods
	static void startDebugLog(std::string info = "[no Info]");  
	static void startErrorLog(std::string info = "[no Info]"); 
	static void writeToDebugLog(std::string text);
	static void writeToErrorLog(std::string text);
	static std::string getCaller();
	static std::string getLevelTag(int level);
	static std::string getLevelColor(int level);
	static std::string getStandardColor();
  

private: //fields
	
	static const int highestLevel;
	
	static int level;
	static int logLevel;
  
	static std::string tag;
	static std::string applicationInfo;
  
	static std::ofstream* debugLog;
	static std::ofstream* errorLog;
	  
	static std::string logPath;
	static std::string fullDebugLogPath;
	static std::string fullErrorLogPath;
	  
	static std::string debugLogName;
	static std::string errorLogName;
	  
	static bool alreadyLoggedDebug;
	static bool alreadyLoggedError;
	  
	
#ifndef WIN32	  
	static pthread_mutex_t debugLock;
	static pthread_mutex_t errorLock;
	static pthread_mutex_t outputLock;
#endif  
	  
	static bool doShowParams;
	static bool doShowFunctionNames;
	static bool doShowFileNames;
	static bool doShowLineNumbers;
	static bool doLog;
	static bool doUseColors;
	  
	
	/**
	 * The function name filter is a set of strings the should be filtered (duh!) when
	 * determining the name of a calling function.
	 * Methods of this class should always be filtered, because they will always be the
	 * last method(s) on the call stack.
	 * However, the call stack can be further filled with methods you never notice when 
	 * making calls to this class, e.g. when working with Qt, so there may be further class
	 * names you would wish to filter.
	 * You do that by calling #addFunctionFilterString(std::string)
	 **/
	static std::vector<std::string>* functionNameFilter;
	
  
  
};

#endif /* ifdef DEBUG */
#endif /*!OUTPUT_H*/
